/* $Id$ */

/*
 * Copyright (C) 2008  Mikhail Vorozhtsov
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (the file COPYING). If not, see
 * <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <glib.h>
#include <gtk/gtk.h>
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
#include <libwnck/libwnck.h>

#if ENABLE_NLS
# include <libintl.h>
# define _(STRING) gettext (STRING)
#else
# define _(STRING) (STRING)
#endif

/*
 * "Fake" gettext macro to help xgettext collect strings
 * that are translated by Glib automatically.
 */
#define F_(STRING) (STRING)

#if STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# if HAVE_STDLIB_H
#   include <stdlib.h>
# else
extern void exit (int);
# endif
#endif

#if HAVE_STRING_H
# if !STDC_HEADERS
#   if HAVE_MEMORY_H
#     include <memory.h>
#   else
extern void *memset (void *, int, unsigned long);
#   endif
# endif
# include <string.h>
#else
extern int strcmp (const char *, const char *);
extern void *memset (void *, int, unsigned long);
#endif

struct _WorkspaceData
{
  int idx;
  GtkWidget *menu_item;
  GtkWidget *empty_menu_item;
  GHashTable *item_by_xid;
};

typedef struct _WorkspaceData WorkspaceData;

struct _WindowData
{
  gulong xid;
  int ws_idx;
};

typedef struct _WindowData WindowData;

GQuark wsd_quark;
GQuark wd_quark;

WnckScreen *screen;
GHashTable *workspaces;
GtkWidget *menu;

static gint menu_item_position (GtkMenuItem *menu_item);

static GtkWidget *create_workspace_menu_item (WnckWorkspace *);
static GtkWidget *create_empty_menu_item ();
static void update_workspace_menu_item (GtkMenuItem *);
static GtkWidget *create_window_menu_item (WnckWindow *);
static void update_window_menu_item (GtkMenuItem *);

static void sync_screen ();
static void sync_workspace (WnckWorkspace *);
static void sync_window (WnckWindow *);

static void workspace_created_cb (WnckScreen *, WnckWorkspace *, gpointer);
static void workspace_destroyed_cb (WnckScreen *, WnckWorkspace *, gpointer);
static void workspace_name_changed_cb (WnckWorkspace *, gpointer);

static void window_opened_cb (WnckScreen *, WnckWindow *, gpointer);
static void window_closed_cb (WnckScreen *, WnckWindow *, gpointer);
static void window_workspace_changed_cb (WnckWindow *, gpointer);
static void window_something_changed_cb (WnckWindow *, gpointer);
static void window_state_changed_cb (WnckWindow *, WnckWindowState,
                                     WnckWindowState, gpointer);

static void active_workspace_changed_cb (WnckScreen *, WnckWorkspace *,
                                         gpointer);
static void window_stacking_changed_cb (WnckScreen *, gpointer);
static void active_window_changed_cb (WnckScreen *, WnckWindow *, gpointer);

static void menu_hide_cb (GtkWidget *, gpointer);
static void menu_position_fn (GtkMenu *, gint *, gint *, gboolean *, gpointer);

static void menu_item_activated_cb (GtkMenuItem *, gpointer);

static gint
menu_item_position (GtkMenuItem *menu_item)
{
  GList *menu_items = gtk_container_get_children (GTK_CONTAINER (menu));
  gint result = g_list_index (menu_items, menu_item);
  g_list_free (menu_items);
  return result;
}

static GtkWidget *
create_workspace_menu_item (WnckWorkspace *ws)
{
  GtkWidget *menu_item = gtk_menu_item_new ();
  GtkWidget *frame = gtk_frame_new (NULL);
  GtkWidget *label = gtk_label_new (NULL);

  gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);

  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
  gtk_container_add (GTK_CONTAINER (frame), label);

  gtk_widget_set_sensitive (menu_item, FALSE);
  gtk_container_add (GTK_CONTAINER (menu_item), frame);

  return menu_item;
}

static GtkWidget *
create_empty_menu_item ()
{
  GtkWidget *menu_item = gtk_menu_item_new ();
  GtkWidget *hbox = gtk_hbox_new (FALSE, 5);
  GtkWidget *left_separator = gtk_hseparator_new ();
  GtkWidget *right_separator = gtk_hseparator_new ();
  GtkWidget *label = gtk_label_new ("Empty");

  gtk_box_pack_start (GTK_BOX (hbox), left_separator, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_box_pack_end (GTK_BOX (hbox), right_separator, TRUE, TRUE, 0);

  gtk_container_add (GTK_CONTAINER (menu_item), hbox);

  return menu_item;
}

static void
update_workspace_menu_item (GtkMenuItem *menu_item)
{
  WorkspaceData *wsd = g_object_get_qdata (G_OBJECT (menu_item), wsd_quark);
  WnckWorkspace *ws = wnck_screen_get_workspace (screen, wsd->idx);
  GtkWidget *label
    = gtk_bin_get_child (
        GTK_BIN (gtk_bin_get_child (GTK_BIN ((menu_item)))));
  gchar *markup
    = g_markup_printf_escaped (
        ws == wnck_screen_get_active_workspace (screen)
        ? "<b>%s</b>" : "%s", wnck_workspace_get_name (ws));

  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);
}

static GtkWidget *
create_window_menu_item (WnckWindow *window)
{
  GtkWidget *menu_item = gtk_menu_item_new ();
  GtkWidget *hbox = gtk_hbox_new (FALSE, 5);
  GtkWidget *image = gtk_image_new_from_pixbuf (NULL);
  GtkWidget *label = gtk_label_new (NULL);

  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);

  gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
  gtk_box_pack_end (GTK_BOX (hbox), label, TRUE, TRUE, 0);

  gtk_container_add (GTK_CONTAINER (menu_item), hbox);

  return menu_item;
}

static void
update_window_menu_item (GtkMenuItem *menu_item)
{
  WindowData *wd = g_object_get_qdata (G_OBJECT (menu_item), wd_quark);
  WnckWindow *window = wnck_window_get (wd->xid);
  GList *children = gtk_container_get_children (
                      GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (menu_item))));
  GtkWidget *image = children->data;
  GtkWidget *label = children->next->data;
  gchar *title = g_markup_escape_text (wnck_window_get_name (window), -1);
  gchar *tag_open
    = g_strdup_printf ("%s%s%s",
        wnck_window_is_pinned (window) ? "<i>" : "",
        wnck_window_is_active (window) ? "<b>" : "",
        (wnck_window_get_state (window) 
         & (WNCK_WINDOW_STATE_DEMANDS_ATTENTION
            | WNCK_WINDOW_STATE_URGENT)) ? "<u>" : "");
  gchar *tag_close
    = g_strdup_printf ("%s%s%s", 
        (wnck_window_get_state (window) 
         & (WNCK_WINDOW_STATE_DEMANDS_ATTENTION
            | WNCK_WINDOW_STATE_URGENT)) ? "</u>" : "",
        wnck_window_is_active (window) ? "</b>" : "",
        wnck_window_is_pinned (window) ? "</i>" : "");
  gchar *markup = g_strconcat (tag_open, title, tag_close, NULL);

  g_list_free (children);
  g_free (tag_open);
  g_free (tag_close);
  g_free (title);

  gtk_image_set_from_pixbuf (
    GTK_IMAGE (image), wnck_window_get_mini_icon (window));
  gtk_label_set_markup (GTK_LABEL (label), markup);

  g_free (markup);
}

static void
sync_workspace (WnckWorkspace *ws)
{
  int ws_idx = wnck_workspace_get_number (ws);
  WorkspaceData *wsd = g_hash_table_lookup (
                         workspaces, GINT_TO_POINTER (ws_idx));
  gint pos, ws_mi_pos = menu_item_position (GTK_MENU_ITEM (wsd->menu_item));
  GList *windows = wnck_screen_get_windows_stacked (screen);
  gboolean empty_p = TRUE;

  if (windows)
    windows = g_list_last (windows);

  for (pos = ws_mi_pos; windows; windows = g_list_previous (windows))
    {
      WnckWindow *window = windows->data;

      if (!wnck_window_is_on_workspace (window, ws)
          || wnck_window_get_state (window) & WNCK_WINDOW_STATE_SKIP_PAGER)
        continue;

      empty_p = FALSE;
      pos += 1;
      gulong xid = wnck_window_get_xid (window);
      GtkWidget *menu_item = g_hash_table_lookup (
                               wsd->item_by_xid, GINT_TO_POINTER (xid));

      if (menu_item == NULL)
        {
          menu_item = create_window_menu_item (window);
          WindowData *wd = g_new (WindowData, 1);

          wd->xid = xid;
          wd->ws_idx = ws_idx;

          g_signal_connect (G_OBJECT (menu_item), "activate",
                            G_CALLBACK (menu_item_activated_cb), NULL);

          g_object_set_qdata_full (G_OBJECT (menu_item), wd_quark, wd, g_free);
          update_window_menu_item (GTK_MENU_ITEM (menu_item));

          g_hash_table_insert (wsd->item_by_xid, GINT_TO_POINTER (xid),
                               menu_item);

          gtk_menu_insert (GTK_MENU (menu), menu_item, pos);
          gtk_widget_show_all (menu_item);
        }
      else
        gtk_menu_reorder_child (GTK_MENU (menu), menu_item, pos);
    }

  gint next_ws_mi_pos;
  GList *menu_items = gtk_container_get_children (GTK_CONTAINER (menu));
  GList *item = g_list_nth (menu_items, pos + 1);

  if (ws_idx == g_hash_table_size (workspaces) - 1)
    next_ws_mi_pos = g_list_length (menu_items);
  else
    {
      WorkspaceData *wsd = g_hash_table_lookup (
                             workspaces, GINT_TO_POINTER (ws_idx + 1));
      next_ws_mi_pos = menu_item_position (GTK_MENU_ITEM (wsd->menu_item));
    }

  for (pos += 1; pos < next_ws_mi_pos; ++pos, item = g_list_next (item))
    {
      GtkWidget *menu_item = (GtkWidget *) item->data;
      WindowData *wd = g_object_get_qdata (G_OBJECT (menu_item), wd_quark);
      g_hash_table_remove (wsd->item_by_xid, GINT_TO_POINTER (wd->xid));
      gtk_container_remove (GTK_CONTAINER (menu), menu_item);
    }

  if (empty_p)
    {
      gtk_menu_insert (GTK_CONTAINER (menu), wsd->empty_menu_item,
                       ws_mi_pos + 1);
      gtk_widget_show_all (GTK_WIDGET (wsd->empty_menu_item));
    }

  g_list_free (menu_items);
}

static void
sync_screen ()
{
  GHashTableIter iter;
  gpointer key, value;

  g_hash_table_iter_init (&iter, workspaces);

  while (g_hash_table_iter_next (&iter, &key, &value))
    sync_workspace (wnck_screen_get_workspace (screen, GPOINTER_TO_INT (key)));
}

static void
sync_window (WnckWindow *window)
{
  WnckWindowType type = wnck_window_get_window_type (window);

  if (type != WNCK_WINDOW_NORMAL && type != WNCK_WINDOW_DIALOG)
    return;

  if (wnck_window_is_pinned (window))
    sync_screen (wnck_window_get_screen (window));
  else
    sync_workspace (wnck_window_get_workspace (window));
}

static void
workspace_created_cb (WnckScreen *screen, WnckWorkspace *ws, gpointer data)
{
  GtkWidget *menu_item = create_workspace_menu_item (ws);
  GtkWidget *empty_menu_item = create_empty_menu_item ();
  int ws_idx = wnck_workspace_get_number (ws);
  WorkspaceData *wsd = g_new (WorkspaceData, 1);
  WindowData *wd = g_new (WindowData, 1);

  wsd->idx = wnck_workspace_get_number (ws);
  wsd->menu_item = menu_item;
  wsd->empty_menu_item = empty_menu_item;
  wsd->item_by_xid = g_hash_table_new (g_direct_hash, g_direct_equal);

  g_object_ref (G_OBJECT (empty_menu_item));

  g_hash_table_insert (workspaces, GINT_TO_POINTER (ws_idx), wsd);

  wd->xid = 0;
  wd->ws_idx = wnck_workspace_get_number (ws);

  g_signal_connect (G_OBJECT (empty_menu_item), "activate",
                    G_CALLBACK (menu_item_activated_cb), NULL);

  g_object_set_qdata_full (G_OBJECT (menu_item), wsd_quark, wsd, g_free);
  g_object_set_qdata_full (G_OBJECT (empty_menu_item), wd_quark, wd, g_free);
  update_workspace_menu_item (GTK_MENU_ITEM (menu_item));

  gtk_menu_append (GTK_MENU (menu), menu_item);
  gtk_widget_show_all (menu_item);

  sync_workspace (ws);

  g_signal_connect (G_OBJECT (ws), "name-changed",
                    G_CALLBACK (workspace_name_changed_cb), NULL);

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
workspace_destroyed_cb (WnckScreen *screen, WnckWorkspace *ws, gpointer data)
{
  int ws_idx = wnck_workspace_get_number (ws);
  WorkspaceData *wsd = g_hash_table_lookup (
                         workspaces, GINT_TO_POINTER (ws_idx));
  GHashTableIter iter;
  gpointer key, value;

  g_hash_table_iter_init (&iter, wsd->item_by_xid);

  while (g_hash_table_iter_next (&iter, &key, &value))
    {
      GtkWidget *menu_item = (GtkWidget *) value;
      gtk_container_remove (GTK_CONTAINER (menu), menu_item);
    }

  gtk_container_remove (GTK_CONTAINER (menu), wsd->menu_item);
  if (gtk_widget_get_parent (wsd->empty_menu_item))
    gtk_container_remove (GTK_CONTAINER (menu), wsd->empty_menu_item);
  g_hash_table_remove_all (wsd->item_by_xid);
  g_free (wsd->item_by_xid);
  g_object_unref (wsd->empty_menu_item);
  g_free (wsd);

  g_hash_table_remove (workspaces, GINT_TO_POINTER (ws_idx));

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
workspace_name_changed_cb (WnckWorkspace *ws, gpointer data)
{
  WorkspaceData *wsd
    = g_hash_table_lookup (
        workspaces, GINT_TO_POINTER (wnck_workspace_get_number (ws)));
  update_workspace_menu_item (GTK_MENU_ITEM (wsd->menu_item));
  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_opened_cb (WnckScreen *screen, WnckWindow *window, gpointer data)
{
  g_signal_connect (G_OBJECT (window), "workspace-changed",
                    G_CALLBACK (window_workspace_changed_cb), NULL);
  g_signal_connect (G_OBJECT (window), "name-changed",
                    G_CALLBACK (window_something_changed_cb), NULL);
  g_signal_connect (G_OBJECT (window), "icon-changed",
                    G_CALLBACK (window_something_changed_cb), NULL);
  g_signal_connect (G_OBJECT (window), "state-changed",
                    G_CALLBACK (window_state_changed_cb), NULL);

  sync_window (window);

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_closed_cb (WnckScreen *screen, WnckWindow *window, gpointer data)
{
  sync_window (window);
  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_workspace_changed_cb (WnckWindow *window, gpointer data)
{
  sync_screen ();
  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_something_changed_cb (WnckWindow *window, gpointer data)
{
  gulong xid = wnck_window_get_xid (window);

  if (wnck_window_is_pinned (window))
    {
      GHashTableIter iter;
      gpointer key, value;

      g_hash_table_iter_init (&iter, workspaces);

      while (g_hash_table_iter_next (&iter, &key, &value))
        {
          WorkspaceData *wsd = value;
          GtkWidget *menu_item = g_hash_table_lookup (
                                   wsd->item_by_xid, GINT_TO_POINTER (xid));

          if (menu_item)
            update_window_menu_item (GTK_MENU_ITEM (menu_item));
        }
    }
  else
    {
      WorkspaceData *wsd
        = g_hash_table_lookup (
            workspaces,
            GINT_TO_POINTER (wnck_workspace_get_number (
                               wnck_window_get_workspace (window))));
      GtkWidget *menu_item = g_hash_table_lookup (
                               wsd->item_by_xid, GINT_TO_POINTER (xid));

      if (menu_item)
        update_window_menu_item (GTK_MENU_ITEM (menu_item));
    }

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_state_changed_cb (WnckWindow *window, WnckWindowState changed_mask,
                         WnckWindowState new_state, gpointer data)
{
  if (changed_mask
      & (WNCK_WINDOW_STATE_DEMANDS_ATTENTION
         | WNCK_WINDOW_STATE_URGENT))
    window_something_changed_cb (window, data);

  if (changed_mask & WNCK_WINDOW_STATE_SKIP_PAGER)
    {
      sync_window (window);
      gtk_menu_reposition (GTK_MENU (menu));
    }
}

static void
active_workspace_changed_cb (WnckScreen *screen, WnckWorkspace *prev_ws,
                             gpointer data)
{
  WnckWorkspace *ws = wnck_screen_get_active_workspace (screen);

  if (prev_ws)
    {
      WorkspaceData *wsd
        = g_hash_table_lookup (
            workspaces,
            GINT_TO_POINTER (wnck_workspace_get_number (prev_ws)));
      update_workspace_menu_item (GTK_MENU_ITEM (wsd->menu_item));
    }

  if (ws)
    {
      WorkspaceData *wsd
        = g_hash_table_lookup (
            workspaces,
            GINT_TO_POINTER (wnck_workspace_get_number (ws)));
      update_workspace_menu_item (GTK_MENU_ITEM (wsd->menu_item));
    }

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
window_stacking_changed_cb (WnckScreen *screen, gpointer data)
{
  sync_screen (screen);
  gtk_menu_reposition (GTK_MENU (menu));
}

static void
active_window_changed_cb (WnckScreen *screen, WnckWindow *prev_window,
                          gpointer data)
{
  WnckWindow *window = wnck_screen_get_active_window (screen);

  if (prev_window)
    window_something_changed_cb (prev_window, data);
  if (window)
    window_something_changed_cb (window, data);

  gtk_menu_reposition (GTK_MENU (menu));
}

static void
menu_hide_cb (GtkWidget *widget, gpointer data)
{
  gtk_main_quit ();
}

static void
menu_position_fn (GtkMenu *menu, gint *x, gint *y, gboolean *push_in,
                  gpointer data)
{
  GtkRequisition req;

  gtk_widget_size_request (GTK_WIDGET (menu), &req);

  *x = (wnck_screen_get_width (screen) - req.width) / 2;
  *y = (wnck_screen_get_height (screen) - req.height) / 2;
  *push_in = FALSE;
}

static void
menu_item_activated_cb (GtkMenuItem *menu_item, gpointer data)
{
  WindowData *wd = g_object_get_qdata (G_OBJECT (menu_item), wd_quark);
  WnckWorkspace *ws = wnck_screen_get_workspace (screen, wd->ws_idx);
  WnckWindow *window = wnck_window_get (wd->xid);

  wnck_workspace_activate (ws, gtk_get_current_event_time ());

  if (window)
    wnck_window_activate (window, gtk_get_current_event_time ());
}

static void
print_version_and_exit ()
{
  g_print ("%s\n", PACKAGE_STRING);
  exit (0);
}

int
main (int argc, char **argv)
{
  GError *error = NULL;

  g_type_init ();
  gtk_set_locale ();

  bindtextdomain (GETTEXT_DOMAIN, LOCALEDIR);
  textdomain (GETTEXT_DOMAIN);

  GOptionContext *opt_ctx = g_option_context_new (NULL);

  g_option_context_add_group (opt_ctx, gtk_get_option_group (TRUE));
  g_option_context_add_main_entries (
    opt_ctx,
    (GOptionEntry []) {
      { "version", 0, G_OPTION_FLAG_NO_ARG,
        G_OPTION_ARG_CALLBACK, print_version_and_exit,
        F_("Print program version and exit."), NULL },
      { NULL, 0, 0, 0, NULL, NULL, NULL }
    }, NULL);

  g_option_group_set_translation_domain (
    gtk_get_option_group (TRUE), GETTEXT_DOMAIN);
  g_option_group_set_translation_domain (
    g_option_context_get_main_group (opt_ctx), GETTEXT_DOMAIN);

  if (!g_option_context_parse (opt_ctx, &argc, &argv, &error))
    {
      g_printerr ("%s: %s.\n", PACKAGE, error->message);
      return 1;
    }

  g_option_context_free (opt_ctx);

  wsd_quark = g_quark_from_static_string ("workspace");
  wd_quark = g_quark_from_static_string ("window");

  workspaces = g_hash_table_new (g_direct_hash, g_direct_equal);

  menu = gtk_menu_new ();

  gtk_widget_set_name (gtk_widget_get_parent (menu), "wilt");
  gtk_widget_set_name (menu, "List");

  g_signal_connect (G_OBJECT (menu), "hide", G_CALLBACK (menu_hide_cb), NULL);

  screen = wnck_screen_get_default ();

  g_signal_connect (G_OBJECT (screen), "workspace-created",
                    G_CALLBACK (workspace_created_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "workspace-destroyed",
                    G_CALLBACK (workspace_destroyed_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "active-workspace-changed",
                    G_CALLBACK (active_workspace_changed_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "window-opened",
                    G_CALLBACK (window_opened_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "window-closed",
                    G_CALLBACK (window_closed_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "window-stacking-changed",
                    G_CALLBACK (window_stacking_changed_cb), NULL);
  g_signal_connect (G_OBJECT (screen), "active-window-changed",
                    G_CALLBACK (active_window_changed_cb), NULL);

  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, menu_position_fn, NULL, 0,
                  gtk_get_current_event_time ());

  wnck_screen_force_update (screen);

  WnckWorkspace *active_ws = wnck_screen_get_active_workspace (screen);
  WnckWindow *active_window = wnck_screen_get_active_window (screen);
  WorkspaceData *wsd
    = g_hash_table_lookup (
        workspaces, GINT_TO_POINTER (wnck_workspace_get_number (active_ws)));

  {
    gboolean selected_p = FALSE;

    if (active_window)
      {
        GtkWidget *menu_item
          = g_hash_table_lookup (
              wsd->item_by_xid,
              GINT_TO_POINTER (wnck_window_get_xid (active_window)));

        if (menu_item)
          {
            gtk_menu_shell_select_item (GTK_MENU_SHELL (menu), menu_item);
            selected_p = TRUE;
          }
      }

    if (!selected_p)
      {
        GList *menu_items = gtk_container_get_children (GTK_CONTAINER (menu));
        gtk_menu_shell_select_item (
          GTK_MENU_SHELL (menu),
          GTK_WIDGET (
            g_list_nth (
              menu_items,
              g_list_index (menu_items, wsd->menu_item) + 1)->data));
        g_list_free (menu_items);
      }
  }

  gtk_menu_reposition (GTK_MENU (menu));

  gtk_main ();

  return 0;
}

